Speed exposes coordination problems that were already there. We tested AI-assisted development on a real production client project, expecting tooling to be the main challenge. It wasn't. Once code started moving faster than before, business analysts, architects, developers, and designers all needed the same thing: a reliable, shared answer to one question. What exactly are we building, and whose version of that decision is current?
The problem wasn't the AI tools themselves. It was the lack of a single agreed source of truth. Product information was spread across documents, acceptance criteria, vision, goals, roadmap, code, and tests. Every role on the team read a slightly different version. In this article, I'll break down what we built to fix that. It's a single source of truth that keeps every role and every team working from the same version of reality — and I'll walk through what it's already delivered, and where it still falls short.
The coordination problem that speed exposes
That matters for reasons that go beyond code quality. When roles and teams don't share a single source of truth, coordination costs show up everywhere. Onboarding takes longer. Cross-team disputes about scope get harder to settle. Reviews drag. AI doesn't remove that ambiguity — it just turns it into code, and into everyone's business, faster.
An AI agent working with fragmented context has no better luck than a person does. It can't reliably know which source is current, which decision supersedes another, or what the team actually agreed to build.
AI coding tools are good at producing output. The harder question — for one developer or for a cross-functional team — is whether that output reflects the decisions everyone actually agreed to.
If requirements, design decisions, and implementation history are scattered across different places, adding an AI agent doesn't fix the fragmentation. It gives one more contributor, working faster than the rest, more context to misread. The same fragmentation that used to slow down a new hire's first month now slows down every actor touching the system — human or automated. Sometimes it doesn't just slow things down. It quietly sends them the wrong way.
None of this is unique to engineering. A product manager who can't see what a development team already committed to is fighting the same fragmentation, just from a different desk. So is a QA team validating against acceptance criteria nobody updated. AI-assisted development speeds up the clock for all of them at once.
What misalignment actually costs
The cost isn't hypothetical. Three data points, from two 2026 studies, describe the same pattern from different angles.
The data behind the intuition
A 2026 GitClear analysis of 623 million code changes found duplicated code blocks up 81%, error-masking constructs up 47%, and two-week code churn up 15%. Actual refactoring fell 70% compared with 2022.
Heavy AI users produced four to ten times more raw output than non-users. Measured against their own pre-AI performance, though, the same developers gained only about 25% in velocity.
Most of the headline number was already there before AI. And without one current, shared source of truth, volume quickly turns into duplicated logic and code nobody fully trusts.
Foundations, not tools, decide the outcome
Google Cloud's 2026 DORA report modeled a 500-person engineering organization and found a real number behind the AI-adoption hype: a 39% first-year ROI. That's $11.6 million in value against $8.4 million invested, paying back in roughly eight months. Projected out, the return reaches 727% over three years.
Nathen Harvey, who leads the DORA team, put it plainly. The tools matter less than the organizational system around them — that's where the real returns come from.
Stanford research cited in the same report makes the split concrete. AI delivers 35–40% gains on simple, greenfield work with few dependencies. On complex legacy systems, that drops to 10% or less, sometimes negative. Complex legacy systems are also, almost by definition, systems too many teams have touched for too long. Nobody kept one place recording why any of it looks the way it does.
The instability tax of moving fast without alignment
The downside case in DORA's model puts a number on what happens without that foundation: change failure rate climbing from 5% to 6% after AI adoption. DORA calls this the instability tax. It isn't a temporary hiccup while teams learn a new tool. It shows up when output outpaces an organization's ability to verify and coordinate it — and nobody adjusts the process to close that gap.
The tax comes from two places. Reviewers suddenly have more to check, because AI generates more, faster, than any single team member did before it. And the review and hand-off workflow around that output usually stays the same. Same approval steps. Same assumption that a merged pull request means every affected team understood what changed. Neither assumption survives the volume increase.
Slowing AI down won't close that gap. Giving every role touching the system — not just the developer reviewing a pull request — something concrete to check output against will.
One source of truth: how it's structured
That's exactly the layer spec-driven development is built to provide.
A single, living specification
The specification lives in one versioned repository. It holds product intent, requirements, design decisions, implementation tasks, and their full history. That's the reference point people and AI agents both work from, instead of five different ones. History matters here because a current decision is easier to trust when the team can also see what changed, when, and why.
We didn't want another document people forget to update. We wanted the specification to become the place where product and engineering decisions get recorded before implementation begins. That's true for every role that touches the product, not only for engineering.
We built this framework ourselves and named it Rootspec. It's our own abstraction on top of spec-driven development, not a published framework that happens to share the name.
The hierarchy — from vision to task
The hierarchy starts at the product level, with vision, goal, and roadmap. Those break down into capabilities and features, then into specific, testable requirements written in given-when-then notation. Each requirement connects to the tasks needed to implement it in the relevant component. A requirement that spans more than one component gets a separate task for each one it touches.
That structure gives every role a shared reference for discussing a change. A product decision traces down to implementation. An implementation detail traces back up to the requirement that justified it, and the goal that requirement was meant to serve.
Separating what the system does from how it's built
The specification also separates logical design from the technology used to implement it. Requirements describe what the system should do. A separate, swappable binding layer describes how a particular technology or component implements that requirement — the specific frameworks, contracts, and configuration.
That separation means a technology change doesn't require rewriting the product requirements. Moving from Python to Node, for instance, changes the implementation without touching the underlying product intent. That's the part of the work that took the most thinking — and the most cross-role agreement — to get right in the first place.
Nothing gets deleted — full history and validation
The specification isn't just a reference document. It's validated before implementation. Checks cover naming, references, requirement structure, and whether the requirements are actually present. That validation layer expanded over roughly two months, as we found more cases worth checking automatically.
History is preserved the same way. Superseded and deprecated decisions aren't deleted. They stay available, so any role — not just the one who made the original call — can see why the current version looks that way.
The same discipline changes bug triage. Instead of treating every problem as an implementation defect by default, we classify it as one of three things.
- an implementation error.
- a specification error.
- a requirement nobody defined in the first place.
That distinction matters because the fix depends on the cause—code, spec, or a missing requirement —and each belongs to someone different. Classified this way, and on the record, a bug report doesn't turn into an argument about whose scope it was.
Built for cross-role, cross-team handoffs
None of this stays inside engineering. The structure is explicitly built so different roles and different teams can work from it without stepping on each other.
Who owns which artifact — one workflow, several roles
Each stage of the process has an owner, and it isn't always the same person. Writing and refining requirements — the specification step — can sit with a business analyst. Design and the breakdown into tasks are typically an architect's or tech lead's job. On this engagement, a designer also reads directly from the specification before producing UI work. The behavior a screen needs to support is already described there, independent of how it should look.
The tooling doesn't enforce that division. It falls out naturally once every role reads the same structured source, instead of a version filtered through whoever last explained it to them.
Access without exposure — separate repos, separate visibility
The specification lives in a root repository — the single source of truth — but no team is required to work directly inside it. A distribution step copies the relevant slice of the specification into the repository for a specific component. That way, a development team gets exactly the part of the spec their component needs, and nothing else.
That matters more as an organization scales. In a microservices setup, it's entirely reasonable for a team to have no access to the root specification repository. They only need the slice relevant to the service they own. Coordination requires every team to see an accurate, current version of their part.
Seeing when a team has fallen behind
Every component's slice is a copy, taken from the source of truth at a specific point in time. That means we can check how far a copy has drifted from the current version — whether a team is still working against requirements that have since changed upstream. That check turns a question usually answered defensively in a status meeting — “are we behind, and by how much?” — into something anyone can check directly.
A bridge to the tools teams already use
The specification also integrates with the tools non-engineering roles already use day to day. A capability maps to an epic in Jira, a feature to a story, with fields linking each one back to its place in the specification. Right now, that integration runs one direction — from the specification into Jira. A bug reported in Jira is expected to flow back in through the same triage process described earlier, rather than being edited directly at the source.
Coordinated delivery vs. ad hoc delivery
Put the two ways of working side by side, and the real gap is who can answer a basic question—and how long that answer takes to arrive.
| Where does “what we're building” live? | Scattered across tickets, chat threads, and whichever document was last updated | One versioned source, with a full history of changes |
| How does a PM see what a dev team already committed to? | A status meeting, or a guess | A traceable path from goal to requirement to task |
| What happens when a component falls behind the current spec? | Discovered when something breaks | Visible directly, through a drift check |
| Who decides if something is a bug? | Whoever picks up the ticket, case by case | A defined triage step: implementation defect, spec error, or new requirement |
| How fast can a new hire, in any role, contribute? | Weeks of tribal-knowledge transfer | Days, reading one structured source |
| How does AI-generated code get checked? | Ad hoc review, if it happens at all | A validation step gates every change before it merges |
Business outcomes this delivers
Five outcomes emerge consistently once the layer described above is in place.
Faster onboarding across roles
Every role works from the same source: designer, business analyst, architect, developer. On this engagement, the architect currently handles both the architect and business analyst roles. That's a deliberate choice, made to test whether a dedicated analyst can join the workflow later without changing how the source of truth works. Early signs say yes, as long as that analyst follows the same structure as everyone else. The same logic applies to a new hire in any role: read one structured source instead of reconstructing intent from four different tools.
Fewer cross-team disputes over scope
A bug, or a missed handoff between teams, doesn't sit in a queue while people work out whose fault it was. Triage classifies it immediately as an implementation defect, a specification error, or a requirement nobody defined. And the drift check shows whether a team's copy of the spec was simply out of date when the work happened. That classification, made early and kept on the record, is what keeps a scope disagreement from turning into a longer argument than the fix itself.
Lower rework cost
Validation happens before implementation. It catches inconsistent or incomplete requirements while they're still cheap to fix. That could be a naming conflict. It could reference something that doesn't exist yet, or a requirement that contradicts one already approved. None of that reaches a customer as a defect, because none of it reaches a developer's editor in the first place.
Technology independence
Because the specification stays technology-neutral by design, swapping a stack or a vendor doesn't touch the requirements underneath it. For leadership, that shrinks the decision. The requirements stay valid no matter what technology sits under them.
AI adoption leadership can actually defend
Nothing here removes people from the process, and that's deliberate. DORA's own data shows what ungoverned AI adoption costs. The change failure rate climbs from 5% to 6%—an instability tax that eats into whatever ROI the tools were supposed to deliver. A validation gate and a defined triage process directly address that risk. They turn “we're using AI” from a claim about velocity into something concrete and auditable. It's a defined process for making and checking decisions, across every role involved, before anything ships.
What this looks like in practice
A process diagram is one thing. Watching a real change move through the system is more useful. Here's what a small change looked like on the engagement this piece draws from: adding a filter to an existing feature.
It starts as a plain-language request: something like “add a filter to this dashboard by lead status.” An AI agent takes that request through the change process and drafts what's needed: the new requirement, its task, an update to the design file, and an addition to the validation file. All of that happens before anyone writes a line of code. Nobody writes that first draft by hand.
A human reviews it. The architect checks the draft against the original request, then opens a pull request into the shared Rootspec repository — the single source of truth described earlier.
Once approved, the change moves through four steps in sequence. Distribute copies the relevant part of the specification into the component's repository. Export converts it into the format the coding agent works from — BMAT artifacts, in this case. Implement is where a second AI agent writes and tests the code. Validate runs the checks described earlier — naming conventions, references, requirement coverage — before anything merges. A final import step sends the result back to Rootspec, so the source of truth reflects what actually shipped.
The division of labor is narrower than it might sound. The architect's job ends with the pull request into Rootspec: write the change, open the PR, and tag the developer responsible for that component. From there, the developer pulls the latest version and runs distribute, export, implement, validate, and import themselves. They finish with their own pull request into the component's repository.
Two people with separate approvals, and a change that doesn't depend on either person remembering what the other meant.
Where this breaks down — limits and open trade-offs
Everything so far describes the system working as designed. It's worth being just as specific about where it doesn't. We've stayed open about these limitations, and that candor matters because it shows where the approach still needs work.
Sub-agents aren't fully wired into the workflow, and that's on purpose. Early testing showed that connecting them could make them conflict with each other — parallel agents would reconcile their outputs into a compromise that satisfied neither. A human stays involved instead, because an AI agent can still take the work in the wrong direction. In this engagement, that happens often enough to plan for it instead of ignoring it.
AI output isn't consistent from one run to the next. The same request on the same codebase can produce a solid result today and a worse one five minutes later. The system didn't change. The model didn't reproduce the same reasoning twice. The whole industry building with these tools runs into the same problem.
Reviewing the code was always the bottleneck. Reading agent-generated output closely enough to catch the one wrong decision takes real time. So does deciding what to do with every issue the agent surfaces for approval. Raw-output AI ROI calculations often leave both costs out.
Code review stays outside the framework's authority, deliberately. Each component owns it, not the specification layer. Rootspec doesn't dictate how a team writes or reviews code but defines what that code is supposed to do. That separation of concerns came from getting the boundary wrong once.
An early misstep, admitted openly: we converted presale materials directly into capabilities and features. The project didn't go through an additional breakdown once implementation started. In hindsight, that step was still necessary. Even when scope gets defined during presale, it's worth revisiting in detail before committing it to the specification.
Small changes still run through the entire loop. Adding one filter to one dashboard currently means spec, design, task, export, implementation, validation, and import — the full sequence. We're actively considering a lighter workflow for small changes made directly at the component level. Not every change needs to travel through the full source of truth.
None of this is presented as a finished product. We're direct about that. It's under active development, and the automation is only partial. The honest description is closer to “here's what we've learned running this for real” than “here's a solution ready to adopt.”
Key takeaways for engineering and business leaders
The instinct is to judge spec-driven development as a productivity play: will it help the team ship faster? Judge it that way, and you'll miss where the value actually sits.
Code review didn't get adopted because it made anyone type faster. Neither will this. The value sits in the risk it removes before anything ships — and a lot of that risk lives at the seams between roles and teams, not inside any one person's code.
A validated requirement. A design every affected team has already agreed on. A complete, undeletable history of every change. It's all about control: the instability tax DORA puts a number on, and the older, less quantified cost of teams building against different versions of the same plan.
Treat this as a coordination question, and the ROI story becomes much clearer. It doesn't come from generating more code. It comes from a process that lets every role check whether that code is still moving the product in the direction everyone agreed on.